#include "rational.h"

#include <cstdlib>
#include <stdexcept>

using std::invalid_argument;

Rational::Rational(int numerator, int denominator) throw(invalid_argument): numer_(numerator), denom_(denominator) 
{
	if (denominator == 0) throw invalid_argument("Denominator may not be zero.");
	Normalize();
}

Rational& Rational::operator+=(const Rational& summand)
{
	numer_ = numer_ * summand.denom_ + summand.numer_ * denom_;
	denom_ = denom_ * summand.denom_;
	Normalize();
	return *this;
}

Rational& Rational::operator-=(const Rational& summand)
{
	numer_ = numer_ * summand.denom_ - summand.numer_ * denom_;
	denom_ = denom_ * summand.denom_;
	Normalize();
	return *this;
}

Rational& Rational::operator*=(const Rational& multiple)
{
	numer_ = numer_ * multiple.numer_;
	denom_ = denom_ * multiple.denom_;
	Normalize();
	return *this;
}

Rational& Rational::operator/=(const Rational& divisor)
{
	numer_ = numer_ * divisor.denom_;
	denom_ = denom_ * divisor.numer_;
	Normalize();
	return *this;
}

Rational& Rational::operator++()
{
	return *this += Rational(1, 1);
}
	
Rational Rational::operator++(int)
{
	Rational copy = (*this);
	++(*this);
	return copy;
}

Rational& Rational::operator--()
{
	return *this -= Rational(1, 1);
}
	
Rational Rational::operator--(int)
{
	Rational copy = (*this);
	--(*this);
	return copy;
}

Rational::operator double() const
{
	return numer_ / double(denom_);
}

int Rational::Normalize()
{
	int d = Gcd(numer_, denom_);
	numer_ /= d; denom_ /= d;
	return 0;
}

int Rational::Gcd(int numer, int denom)
{
	if (denom == 0)	return numer;
	else return Gcd(denom, numer % denom);
}


Rational operator+(const Rational& summand1, const Rational& summand2)
{
	return Rational(summand1) += summand2;
}

Rational operator-(const Rational& summand1, const Rational& summand2)
{
	return Rational(summand1) -= summand2;
}

Rational operator*(const Rational& multiple1, const Rational& multiple2)
{
	return Rational(multiple1) *= multiple2;
}

Rational operator/(const Rational& divident, const Rational& divisor)
{
	return Rational(divident) /= divisor;
}

bool operator==(const Rational& comparand1, const Rational& comparand2)
{
	return comparand1.numer_ == comparand2.numer_ && comparand1.denom_ == comparand2.denom_;
}

bool operator!=(const Rational& comparand1, const Rational& comparand2)
{
	return ! (comparand1 == comparand2);
}

bool operator>(const Rational& comparand1, const Rational& comparand2)
{
	Rational delta = comparand1 - comparand2;
	return delta.numer_ * delta.denom_ > 0;
}

bool operator<(const Rational& comparand1, const Rational& comparand2)
{
	Rational delta = comparand1 - comparand2;
	return delta.numer_ * delta.denom_ < 0;
}

bool operator>=(const Rational& comparand1, const Rational& comparand2)
{
	return comparand1 > comparand2 || comparand1 == comparand2;
}

bool operator<=(const Rational& comparand1, const Rational& comparand2)
{
	return comparand1 < comparand2 || comparand1 == comparand2;
}
